﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace CAP.Mathematics
{
    public struct Vector
    {
        #region Eigenschaften
        public float X;
        public float Y;
        #endregion Eigenschaften

        #region Methoden
        /// <summary>
        /// Initialisiert die Struktur.
        /// </summary>
        /// <param name="x">Wert für X.</param>
        /// <param name="y">Wert für Y.</param>
        public Vector(float x, float y)
        {
            this.X = x;
            this.Y = y;
        }

        /// <summary>
        /// Initialisiert die Struktur.
        /// </summary>
        /// <param name="originColor">Der Ausgangspunkt.</param>
        /// <param name="targetColor">Der Zielpunkt.</param>
        public Vector(Point origin, Point target)
        {
            this.X = target.X - origin.X;
            this.Y= target.Y- origin.Y;
        }

        /// <summary>
        /// Initialisiert die Struktur.
        /// </summary>
        /// <param name="originColor">Der Ausgangspunkt.</param>
        /// <param name="targetColor">Der Zielpunkt.</param>
        public Vector(PointF origin, PointF target)
        {
            this.X = target.X - origin.X;
            this.Y = target.Y - origin.Y;
        }

        /// <summary>
        /// Berechnet die Richtung eines Vektors für den angegebenen Winkel vom  Nullpunkt.
        /// </summary>
        /// <param name="angle">Der (Quad)Winkel des Vektors.</param>
        public Vector(float angle)
        {
            float degatan = (-angle - 90) - (angle >= 270 ? 360 : (angle >= 90 ? 180 : 0));
            float tan = Math.Abs((float)Math.Tan(Converter.ToRAD(degatan)));

            this.X = angle >= 270 ? tan : (angle >= 90 ? -tan : tan);
            this.Y = angle >= 180 ? -1 : 1;
        }

        /// <summary>
        /// Normalisiert den Vektor.
        /// </summary>
        public void Normalize()
        {
            float absolute = GetAbsoluteValue();
            if (absolute == 0) return;
            this.X = this.X / absolute;
            this.Y = this.Y / absolute;
        }

        /// <summary>
        /// Verlängert den Betrag des Vektors auf einen bestimmten Wert.
        /// </summary>
        /// <param name="length">Die angestrebte Känge des Vektors.</param>
        public void FitToLength(float length)
        {
            Normalize();
            this.X = this.X * length;
            this.Y = this.Y * length;
        }

        /// <summary>
        /// Gibt den Betrag des Vektors an.
        /// Mathematisch: |vt|
        /// </summary>
        /// <returns>Der Betrag des Vektors</returns>
        public float GetAbsoluteValue()
        {
            return (float)Math.Sqrt(Math.Pow(X, 2) + Math.Pow(Y, 2));
        }

        /// <summary>
        /// Gibt den Richtungswinkel des Vektors an.
        /// 
        /// Quadranten:     1 entspricht 0 - 90°
        /// 2|1             2 entspricht 90 - 180°
        /// -+-             3 entspricht 180 - 270°
        /// 3|4             4 entspricht 270 - 360°
        /// </summary>
        /// <returns>Der Winkel.</returns>
        public double GetQuadrantAngle()
        {
            return Converter.ToDEG(Math.Atan(Y / X)) + (X >= 0 ? (Y >= 0 ? 0.0f : 360.0f) : 180.0f);
        }

        /// <summary>
        /// Zur Debugausgabe der bezeichnenden Zeichenkette.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "X = " + X.ToString() + ", Y = " + Y.ToString();
        }

        /// <summary>
        /// Berechnet den Zielpunkt auf Basis eines Ausgangspunktes.
        /// </summary>
        /// <param name="originColor">Der Ausgangspunkt.</param>
        /// <returns>Den Zielpunkt</returns>
        public PointF ToPoint(PointF origin)
        {
            return new PointF((float)(origin.X + X), (float)(origin.Y + Y));
        }

        /// <summary>
        /// Berechnet den Zielpunkt auf Basis eines Ausgangspunktes.
        /// </summary>
        /// <param name="originColor">Der Ausgangspunkt.</param>
        /// <returns>Den Zielpunkt</returns>
        public Point ToPoint(Point origin)
        {
            return new Point((int)(origin.X + X), (int)(origin.Y + Y));
        }
        #endregion Methoden
    }
}
